home *** CD-ROM | disk | FTP | other *** search
/ Language/OS - Multiplatform Resource Library / LANGUAGE OS.iso / b / b.lha / B / src / bed / comm.c < prev    next >
Encoding:
C/C++ Source or Header  |  1988-11-24  |  7.1 KB  |  397 lines

  1. /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1984. */
  2. static char rcsid[] = "$Header: comm.c,v 2.4 85/08/22 16:00:49 timo Exp $";
  3.  
  4. /*
  5.  * B editor -- Communication with B interpreter.
  6.  */
  7.  
  8. #include "feat.h"
  9. #ifdef BTOP
  10.  
  11. #include <signal.h>
  12. #include <setjmp.h>
  13. #include <ctype.h>
  14.  
  15. #include "b.h"
  16. #include "node.h"
  17. #include "supr.h"
  18. #include "unix.h"
  19. #include "cell.h" /* For winheight */
  20.  
  21. #define TABS 8
  22.  
  23. string unixerror();
  24.  
  25.  
  26. /*
  27.  * Communication to other modules (demo, getc, ...):
  28.  */
  29.  
  30. Visible bool interrupted; /* Set when interrupt caught but not propagated */
  31. Visible bool canjump; /* Set when disrupt() can safely longjmp(jumpback) */
  32. Visible jmp_buf jumpback; /* Set by other module where to jump */
  33.  
  34. /*
  35.  * Pipeline protocol with interpreter:
  36.  */
  37.  
  38. #define ESCAPE '\001' /* Character signalling special function */
  39. #define RESYNC '\177' /* Character signalling acknowledge of interrupt */
  40. #define INTRCHILD SIGTRAP /* Signal to send as interrupt */
  41.  
  42. #ifndef INTERPRETER
  43. #define INTERPRETER "/usr/new/lib/B/bint"
  44. #endif
  45.  
  46. /*
  47.  * Local definitions:
  48.  */
  49.  
  50. #ifndef INTRMSG
  51. #define INTRMSG "*** Interrupted" /* Acknowledges interrupt */
  52. #endif INTRMSG
  53.  
  54. #define Moreinput(stream) ((stream)->_cnt > 0)
  55.  
  56. Hidden int fdown[2]; /* File descriptors for pipe down */
  57. Hidden int fup[2]; /* Pipe up */
  58.  
  59. Hidden int pid; /* Process id of child */
  60.  
  61. Hidden FILE *pdown; /* FILE pointer for pipe down to child process */
  62. Hidden FILE *pup; /* Pipe up */
  63.  
  64. Hidden string interpreter; /* Name of interpreter to be used */
  65.  
  66.  
  67. Hidden char pushback[100]; /* Limited pushback facility */
  68. Hidden int npushback; /* Number of characters pushed back */
  69.  
  70.  
  71. /*
  72.  * Routine to set canjump, do a getc, and clear canjump.
  73.  */
  74.  
  75. Visible int
  76. ffgetc(fp)
  77.     FILE *fp;
  78. {
  79.     register int c;
  80.  
  81.     canjump = Yes;
  82.     c = getc(fp);
  83.     canjump = No;
  84.     return c;
  85. }
  86.  
  87.  
  88. /*
  89.  * Similar for fgets.
  90.  */
  91.  
  92. Visible string
  93. ffgets(buf, len, fp)
  94.     string buf;
  95.     int len;
  96.     FILE *fp;
  97. {
  98.     canjump = Yes;
  99.     buf = fgets(buf, len, fp);
  100.     canjump = No;
  101.     return buf;
  102. }
  103.  
  104.  
  105. /*
  106.  * Assign values to `fdown' and `fup'.
  107.  */
  108.  
  109. Hidden Procedure
  110. getdevices()
  111. {
  112.     if (pipe(fdown) < 0 || pipe(fup) < 0)
  113.         syserr("%s", unixerror("can't pipe"));
  114. }
  115.  
  116.  
  117. /*
  118.  * Do the magic required for child-birth.
  119.  */
  120.  
  121. Hidden Procedure
  122. makechild()
  123. {
  124. #ifdef VFORK
  125.     pid = vfork();
  126. #else VFORK
  127.     pid = fork();
  128. #endif VFORK
  129.     if (pid == -1)
  130.         syserr("%s", unixerror("can't fork"));
  131.     if (pid == 0) /* Child */
  132.         exec_b(); /* Does not return */
  133.     /* Parent */
  134.     close(fdown[0]);
  135.     close(fup[1]);
  136. }
  137.  
  138.  
  139. /*
  140.  * Code executed in the child process.  Never returns.
  141.  * Just dup the pipe ends to files 0, a and 2 (stdin, stdout and stderr),
  142.  * then close the original pipes.
  143.  */
  144.  
  145. Hidden Procedure
  146. exec_b()
  147. {
  148.     close(fdown[1]), close(fup[0]);
  149.     close(0), close(1), close(2);
  150.     dup(fdown[0]), dup(fup[1]), dup(fup[1]);
  151.     close(fdown[0]), close(fup[1]);
  152.     execl(interpreter, interpreter, "-i", (char*)NULL);
  153.     fprintf(stderr, "*** ");
  154.     perror(interpreter);
  155.     _exit(1);
  156. }
  157.  
  158.  
  159. /*
  160.  * Interrupt handler.
  161.  * Usually only the flag `interrupted' is set.
  162.  *
  163.  * When `canjump' is on, it is cleared and we do a longjmp
  164.  * back to where jumpbuf leads us (usually done when a read
  165.  * system call is interrupted, as 4.2BSD tends to continue
  166.  * these rather than have them return with errno = EINTR).
  167.  */
  168.  
  169. Hidden Procedure
  170. disrupt()
  171. {
  172.     interrupted = Yes;
  173.     signal(SIGINT, disrupt);
  174.     if (canjump) {
  175.         canjump = No;
  176.         longjmp(jumpback, 1);
  177.     }
  178. }
  179.  
  180.  
  181. /*
  182.  * Start the B interpreter as a subprocess.
  183.  * Set up communication pipes in pdown, pup.
  184.  */
  185.  
  186. Visible Procedure
  187. start_b(ppdown, ppup)
  188.     FILE **ppdown;
  189.     FILE **ppup;
  190. {
  191.     interpreter = getenv("B_INTERPRETER");
  192.     if (!interpreter)
  193.         interpreter = INTERPRETER;
  194.     getdevices();
  195.     makechild();
  196.     pdown = fdopen(fdown[1], "w");
  197.     pup = fdopen(fup[0], "r");
  198.     if (!pdown || !pup)
  199.         syserr("%s", unixerror("can't fdopen"));
  200.     *ppdown = pdown;
  201.     *ppup = pup;
  202.     signal(SIGINT, disrupt);
  203. }
  204.  
  205.  
  206. /*
  207.  * Routine to be called after each line of data has been passed
  208.  * to the B interpreter; it checks whether the immediate next
  209.  * output is a request for an immediate command, and if so,
  210.  * eats the request and returns Yes.  Otherwise it pushes back the
  211.  * request for later processing by sleur(), and returns No.
  212.  * ***** The prompt parameter is a relict of old times. *****
  213.  */
  214.  
  215. Visible bool
  216. expect(prompt)
  217.     string prompt; /* Only first char used; should be ">" */
  218. {
  219.     register int c;
  220.  
  221.     fflush(pdown);
  222.     if (setjmp(jumpback))
  223.         return No;
  224.     if (npushback)
  225.         c = pushback[--npushback];
  226.     else
  227.         c = ffgetc(pup);
  228.     if (c != ESCAPE) {
  229.         if (c != EOF)
  230.             pushback[npushback++] = c;
  231.         return No;
  232.     }
  233.     if (npushback)
  234.         c = pushback[--npushback];
  235.     else
  236.         c = ffgetc(pup);
  237.     if (c == *prompt)
  238.         return Yes;
  239.     if (c != EOF)
  240.         pushback[npushback++] = c;
  241.     pushback[npushback++] = ESCAPE;
  242.     return No;
  243. }
  244.  
  245.  
  246. Visible int
  247. sleur()
  248. {
  249.     register int c;
  250.     register int x = 0;
  251.     bool show = Yes; /* No when looking for interrupt sync char */
  252.     bool idle = Yes; /* Yes when no output done yet this call */
  253.  
  254.     fflush(pdown);
  255.  
  256.     for (;;) {
  257.         if (interrupted) {
  258.             interrupted = No;
  259.             intrchild();
  260.             show = No;
  261.         }
  262.         if (show && npushback == 0 && !Moreinput(pup))
  263.             fflush(stdout);
  264.         if (setjmp(jumpback))
  265.             continue;
  266.         if (npushback > 0)
  267.             c = pushback[--npushback];
  268.         else
  269.             c = ffgetc(pup);
  270.         if (c == EOF) { /* End-of-file: B interpreter has terminated. */
  271.             fflush(stdout);
  272.             return EOF;
  273.         }
  274.         if (c == RESYNC) {
  275.             /* B interpreter acknowledges interrupt. */
  276.             if (!show) {
  277.                 if (x != 0) putchar('\n');
  278.                 fputs(INTRMSG, stdout);
  279.                 putchar('\n');
  280.                 x = 0;
  281.                 show = Yes;
  282.             }
  283.             continue;
  284.         }
  285.         if (show) {
  286.             if (c != ESCAPE) {
  287.                 putchar(c);
  288.                 switch (c) {
  289.                 case '\t':
  290.                     x = (x/TABS + 1)*TABS;
  291.                     break;
  292.                 case '\b':
  293.                     if (x > 0) --x;
  294.                     break;
  295.                 case '\r':
  296.                 case '\n':
  297.                     x = 0;
  298.                     break;
  299.                 default:
  300.                     if (isascii(c) && isprint(c)
  301.                         || c == ' ') ++x;
  302.                     break;
  303.                 }
  304.             }
  305.             else {
  306.                 /* Control-A: B interpreter needs input. */
  307.                 if (setjmp(jumpback))
  308.                     continue;
  309.                 if (npushback)
  310.                     c = pushback[--npushback];
  311.                 else {
  312.                     c = ffgetc(pup);
  313.                     if (c == EOF) {
  314.                         return EOF;
  315.                     }
  316.                 }
  317.                 if (c == '>') {
  318.                     /* Newline before command prompt */
  319.                     if (x != 0) putchar('\n');
  320.                     x = 0;
  321.                 }
  322.                 setindent(x);
  323.                 fflush(stdout);
  324.                 return c;
  325.             }
  326.         }
  327.     }
  328. }
  329.  
  330.  
  331. /*
  332.  * Send the child a termination signal (SIGTERM).
  333.  */
  334.  
  335. Visible Procedure
  336. termchild()
  337. {
  338.     if (pid) {
  339.         kill(pid, SIGTERM);
  340.         pid = 0;
  341.     }
  342. }
  343.  
  344.  
  345. /*
  346.  * Send the child an interrupt signal.  (By convention, this is SIGTRAP).
  347.  */
  348.  
  349. Visible Procedure
  350. intrchild()
  351. {
  352.     if (pid) {
  353.         kill(pid, INTRCHILD);
  354.         fflush(stdout);
  355.     }
  356. }
  357.  
  358.  
  359. /*
  360.  * Wait for child process and report abnormal exit statuses.
  361.  */
  362.  
  363. Visible Procedure
  364. waitchild()
  365. {
  366.     int k;
  367.     int status;
  368.  
  369.     if (pid) {
  370.         while ((k = wait(&status)) != -1) {
  371.             if (k != pid)
  372. #ifndef SMALLSYS
  373.                 fprintf(stderr, "*** [Pid %d status 0%o]\n", pid, status)
  374. #endif SMALLSYS
  375.                 ;
  376.             else {
  377. #ifndef SMALLSYS
  378.                 if (status&0377)
  379.                     fprintf(stderr, "*** Interpreter killed by signal %d%s\n",
  380.                         status&0177, status&0200 ? " - core dumped" : "");
  381.                 else if (status)
  382.                     fprintf(stderr, "*** Interpreter exit(%d)\n", status>>8);
  383. #endif SMALLSYS
  384.                 pid = 0;
  385.                 break;
  386.             }
  387.         }
  388. #ifndef SMALLSYS
  389.         if (pid)
  390.             fprintf(stderr, "*** Can't get interpreter status\n");
  391. #endif SMALLSYS
  392.         pid = 0;
  393.     }
  394. }
  395.  
  396. #endif BTOP
  397.